#include "ReadInBitsUtil.h"

// return number of bits set
inline unsigned int bitsSetCount(WORD_SIZE bits)
{
    // magic function to caculate how many ones are there
#ifdef WIN32
    unsigned int c; // c accumulates the total bits set in v
    for (c = 0; bits; c++) {
        bits &= bits - 1; // clear the least significant bit set
    }
    return (c);
#else
#ifdef _WIN64
    unsigned int c; // c accumulates the total bits set in v
    for (c = 0; bits; c++) {
        bits &= bits - 1; // clear the least significant bit set
    }
    return (c);
    /*
    bits = ((bits & 0xAAAAAAAAAAAAAAAA) >> 1)  + (bits & 0x5555555555555555);
    bits = ((bits & 0xCCCCCCCCCCCCCCCC) >> 2)  + (bits & 0x3333333333333333);
    bits = ((bits & 0xF0F0F0F0F0F0F0F0) >> 4)  + (bits & 0x0F0F0F0F0F0F0F0F);
    bits = ((bits & 0xFF00FF00FF00FF00) >> 8)  + (bits & 0x00FF00FF00FF00FF);
    bits = ((bits & 0xFFFF0000FFFF0000) >> 16) + (bits & 0x0000FFFF0000FFFF);
    bits = ((bits & 0xFFFFFFFF00000000) >> 32) + (bits & 0x00000000FFFFFFFF);
    return (unsigned int)(bits);
    */
#else
    return(__builtin_popcountll(bits));
#endif
#endif
}

unsigned int bitsStrCompare(CReadInBits r1, CReadInBits r2)
{
    WORD_SIZE bits = (r1.UpperBits ^ r2.UpperBits) | (r1.LowerBits ^ r2.LowerBits);
    return(bitsSetCount(bits));
}

// compare only the last N bases (bits)
unsigned int bitsStrNCompare(CReadInBits r1, CReadInBits r2, unsigned int N)
{
    WORD_SIZE bits = (r1.UpperBits ^ r2.UpperBits) | (r1.LowerBits ^ r2.LowerBits);
    bits <<= (wordSize - N);
    return(bitsSetCount(bits));
    /*
        // magic function to calculate how many ones are there
    #ifdef WIN32
        unsigned int c; // c accumulates the total bits set in v
        for (c = 0; bits; c++) {
            bits &= bits - 1; // clear the least significant bit set
        }
        return (c);
    #else
    #ifdef _WIN64
        unsigned int c; // c accumulates the total bits set in v
        for (c = 0; bits; c++) {
            bits &= bits - 1; // clear the least significant bit set
        }
        return (c);
        bits = ((bits & 0xAAAAAAAAAAAAAAAA) >> 1)  + (bits & 0x5555555555555555);
        bits = ((bits & 0xCCCCCCCCCCCCCCCC) >> 2)  + (bits & 0x3333333333333333);
        bits = ((bits & 0xF0F0F0F0F0F0F0F0) >> 4)  + (bits & 0x0F0F0F0F0F0F0F0F);
        bits = ((bits & 0xFF00FF00FF00FF00) >> 8)  + (bits & 0x00FF00FF00FF00FF);
        bits = ((bits & 0xFFFF0000FFFF0000) >> 16) + (bits & 0x0000FFFF0000FFFF);
        bits = ((bits & 0xFFFFFFFF00000000) >> 32) + (bits & 0x00000000FFFFFFFF);
        return (unsigned int)(bits);

    #else
        return(__builtin_popcountll(bits));
    #endif
    #endif
    */
}

unsigned int bitsStrNCompare(CLongReadInBits r1, CLongReadInBits r2, unsigned int N)
{
    return(bitsStrNCompare(r1.first, r2.first, N) + bitsStrNCompare(r1.second, r2.second, N));
}

// skip the first M base and compare the following N base pairs
unsigned int bitsStrMNCompare(CReadInBits r1, CReadInBits r2, unsigned int M, unsigned int N)
{
    WORD_SIZE bits = (r1.UpperBits ^ r2.UpperBits) | (r1.LowerBits ^ r2.LowerBits);
    bits >>= M;
    bits <<= (wordSize - N);
    return(bitsSetCount(bits));
}

unsigned int bitsStrMNCompare(CLongReadInBits r1, CLongReadInBits r2, unsigned int M, unsigned int N)
{
    return(bitsStrMNCompare(r1.first, r2.first, M, N) + bitsStrMNCompare(r1.second, r2.second, M, N));
}
